﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class LevelGeneration : MonoBehaviour {

	public List<GameObject> rooms = new List<GameObject>();
	public List<GameObject> curRooms = new List<GameObject>();	
	public GameObject secretRoom;
	public GameObject doorPrefab;
	public GameObject shadowWall;
	public enum doorState{NoDoor, NoDoorNeeded, DoorPlaced, Filled, WallNeeded, Interior};
	public GameObject decendDoor;
	GameObject secretRoomDoor;
	int connectionDir = -1;
	bool[,] isFilled = new bool[25,25];
	doorState[,] doors = new doorState[26,51];
	GameObject[,] doorObjects = new GameObject[26,51];
	GameStateManager manager;
	int roomCount;
	int roomCounter = 0;
	GameObject tempRoom;
	Vector2 tempSize;
	Vector2 tempPos;
	void Start () {
		manager = GameObject.Find ("GameStateManager").GetComponent<GameStateManager>();
		ClearArray ();
		ClearArray (true);
		roomCount = Random.Range (7, 10);
		while (roomCounter < roomCount) {
			tempRoom = rooms[Random.Range(0, rooms.Count)];
			tempSize = tempRoom.GetComponent<Room>().size;
			for(int i = 0; i < 100; i++) {
				tempPos.x = Random.Range(0, 24 - (int)tempSize.x);
				tempPos.y = Random.Range(0, 24 - (int)tempSize.y);
				if(CheckBounds(tempSize, tempPos) && CheckConnections(tempSize, tempPos)) {
					PlaceRoom(tempSize, tempPos, tempRoom);
					FillArray(tempSize, tempPos);
					roomCounter++;
					break;
				}
			}
		}
		for(int i = 0; i < 1000; i++) {
			tempPos.x = Random.Range(0, 24 - (int)tempSize.x);
			tempPos.y = Random.Range(0, 24 - (int)tempSize.y);
			if(CheckBounds(secretRoom.GetComponent<Room>().size, tempPos) && CheckConnections(secretRoom.GetComponent<Room>().size, tempPos, true)) {
				PlaceRoom(secretRoom.GetComponent<Room>().size, tempPos, secretRoom, true);
				FillArray(secretRoom.GetComponent<Room>().size, tempPos);
				roomCounter++;
				break;
			}
		}
		foreach (GameObject room in curRooms) {
			if(room != null) {
				if(!room.GetComponent<Room>().secretRoom) 
					room.GetComponent<Room>().GetDoors(doorObjects, doors);
				PlaceShadowWalls(room);
			}
		}
		manager.rooms = curRooms;
		manager.Enable();
	}

	void ClearArray(bool intMode = false) {
		for (int i = 0; i < ((intMode) ? 26 : 25); i++) {
			for (int j = 0; j < ((intMode) ? 51 : 25); j++) {
				if(!intMode)
					isFilled[i,j] = false;
				else {
					doors[i,j] = doorState.WallNeeded;
					if(j % 2 == 0) {
						doors[25, j] = doorState.NoDoorNeeded;
					}
				}
			}
		}
		isFilled [12, 12] = true;
	}
	bool CheckBounds(Vector2 size, Vector2 position) {
		for (int i = 0; i < size.x; i++) {
			for (int j = 0; j < size.y; j++) {
				if(isFilled[(int)position.x + i, (int)position.y + j]) {
					return false;
				}
			}
		}
		return true;
	}
	bool CheckConnections(Vector2 size, Vector2 position, bool secretRoom = false) {
		bool hasConnections = false;
		bool secretDoorPlaced = false;
		for (int i = 0; i < size.x; i++) {
			for (int j = 0; j < 2; j++) {
				if(position.y - 1 + j * (1 + size.y) >= 0 && position.y - 1 + j * (1 + size.y) < 25) {
					if(isFilled[(int)position.x + i, (int)position.y - 1 + j * (1 + (int)size.y)]) {
						hasConnections = true;
						if(secretRoom && connectionDir == -1) {
							if(j == 0) connectionDir = 0;
							if(j == 1) connectionDir = 1;
						}
						if(doors[(int)position.x + i, ((int)position.y + j * (int)size.y) * 2] == doorState.NoDoor || doors[(int)position.x + i, ((int)position.y + j * (int)size.y) * 2] == doorState.WallNeeded) {
							if(!secretRoom || !secretDoorPlaced) {
								GameObject tempObject = (GameObject)GameObject.Instantiate(doorPrefab);
								tempObject.transform.parent = transform;
								tempObject.transform.localPosition = new Vector3((position.x + (float)i - 12f),
								                                            (position.y + (float)j * size.y -12f) - 0.5f,0);
								doors[(int)position.x + i, ((int)position.y + j * (int)size.y) * 2] = doorState.DoorPlaced;
								doorObjects[(int)position.x + i, ((int)position.y + j * (int)size.y) * 2] = tempObject;
								if(secretRoom) secretRoomDoor = tempObject;
								secretDoorPlaced = true;
							}
							else if(secretDoorPlaced) {
								doors[(int)position.x + i, ((int)position.y + j * (int)size.y) * 2] = doorState.WallNeeded;
							}
						}
					} else
						doors[(int)position.x + i, ((int)position.y + j * (int)size.y) * 2] = doorState.WallNeeded;
				}
			}
		}
		for (int i = 0; i < size.y; i++) {
			for (int j = 0; j < 2; j++) {
				if (position.x - 1 + j * (1 + size.x) >= 0 && position.x - 1 + j * (1 + size.x) < 25) {
					if (isFilled [(int)position.x - 1 + j * (1 + (int)size.x), (int)position.y + i]) {
						if(secretRoom && connectionDir == -1) {
							if(j == 0) connectionDir = 2;
							if(j == 1) connectionDir = 3;
						}
						hasConnections = true;
						if (doors [(int)position.x + j * (int)size.x, ((int)position.y + i) * 2 + 1] == doorState.NoDoor || doors [(int)position.x + j * (int)size.x, ((int)position.y + i) * 2 + 1] == doorState.WallNeeded) {
							if(!secretRoom || !secretDoorPlaced) {
								GameObject tempObject = (GameObject)GameObject.Instantiate (doorPrefab);
								tempObject.transform.parent = transform;
								tempObject.transform.localRotation = Quaternion.Euler (0, 0, 90);
								tempObject.transform.localPosition = new Vector3 ((position.x + (float)j * size.x - 12f) - 0.5f,
								                                            (position.y + (float)i - 12f), 0);
								doors [(int)position.x + j * (int)size.x, ((int)position.y + i) * 2 + 1] = doorState.DoorPlaced;
								doorObjects[(int)position.x + j * (int)size.x, ((int)position.y + i) * 2 + 1] = tempObject;
								if(secretRoom) secretRoomDoor = tempObject;
								secretDoorPlaced = true;
							}
							else {
								doors [(int)position.x + j * (int)size.x, ((int)position.y + i) * 2 + 1] = doorState.WallNeeded;
							}
						}
					}
					else
						doors [(int)position.x + j * (int)size.x, ((int)position.y + i) * 2 + 1] = doorState.WallNeeded;
				}
			}
		}
		return hasConnections;
	}
	void FillArray(Vector2 size, Vector2 position) {
		for (int i = 0; i < size.x; i++) {
			for (int j = 0; j < size.y; j++) {
				isFilled[i + (int)position.x,j + (int)position.y] = true;
			}
		}
	}
	void PlaceRoom(Vector2 size, Vector2 position, GameObject room, bool secretRoom = false){
		GameObject holderRoom = (GameObject)Instantiate (room);
		float xOffset = 0;
		float yOffset = 0;
		if (secretRoom) {
			holderRoom.GetComponent<Room>().secretRoom = true;
			holderRoom.GetComponent<Room>().roomDoors.Add(secretRoomDoor);
			switch(connectionDir) {
			case 0:
				yOffset = -.375f;
				break;
			case 1:
				yOffset = .375f;
				break;
			case 2:
				xOffset = -.375f;
				break;
			case 3:
				xOffset = .375f;
				break;
			}
			holderRoom.transform.Find("filler" + connectionDir).tag = "NoShadows";
			Destroy(holderRoom.transform.Find("filler" + connectionDir).gameObject);
		}
		holderRoom.transform.parent = transform;
		holderRoom.transform.localScale = Vector3.one;
		float x = (position.x - 12f - (1-size.x)/2f) + xOffset;
		float y = (position.y - 12f - (1-size.y)/2f) + yOffset;
		holderRoom.transform.localPosition = new Vector3 (x, y, 0);
		holderRoom.transform.Find("Floor").GetComponent<Renderer>().material.color = new Color (Random.Range (0f, 1f), Random.Range (0f, 1f), Random.Range (0f, 1f));
		holderRoom.transform.Find ("UI").GetComponent<Renderer> ().material.color = holderRoom.transform.Find ("Floor").GetComponent<Renderer> ().material.color;
		if(roomCounter + 1 == roomCount) {
			GameObject tempDoor = GameObject.Instantiate(decendDoor);
			tempDoor.transform.parent = transform;
			tempDoor.transform.position = holderRoom.transform.position;
			tempDoor.transform.localScale = new Vector3(0.1f, 0.1f, 1);
			tempDoor.transform.position += new Vector3(0, .001f, 0);
			holderRoom.GetComponent<Room>().roomDoors.Add(tempDoor);
		}
		curRooms.Add(holderRoom);
	}
	void PlaceShadowWalls(GameObject room) {
		BoxCollider[] colliders = room.GetComponentsInChildren<BoxCollider>();
		foreach(BoxCollider collide in colliders) {
			if(!collide.isTrigger && collide.gameObject.tag != "NoShadows"){
				GameObject tempWall = (GameObject)GameObject.Instantiate(shadowWall);
				tempWall.transform.position = collide.bounds.center;
				tempWall.transform.localScale = new Vector3(collide.bounds.extents.x * 2, 100,collide.bounds.extents.z * 2);
				tempWall.transform.parent = room.gameObject.transform;
			}
		}
	}
}
